package com.pxmeta.app.controller.game;

import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.pxmeta.common.core.domain.AjaxResult;
import com.pxmeta.common.core.redis.RedisCache;
import com.pxmeta.common.utils.SecurityUtils;
import com.pxmeta.common.utils.StringUtils;
import com.pxmeta.common.utils.agora.AgoraClient;
import com.pxmeta.dynamic.entity.dto.ReportCircleDTO;
import com.pxmeta.dynamic.entity.dto.ReportPartyDTO;
import com.pxmeta.party.entity.*;
import com.pxmeta.party.entity.dto.*;
import com.pxmeta.party.entity.enums.PartyUserRoleEnum;
import com.pxmeta.party.entity.vo.*;
import com.pxmeta.party.service.*;
import com.pxmeta.skill.service.IUserSkillService;
import com.pxmeta.user.entity.PartyCategory;
import com.pxmeta.user.entity.User;
import com.pxmeta.user.entity.UserBill;
import com.pxmeta.user.entity.vo.AnchorVO;
import com.pxmeta.user.entity.vo.PartyUserBillVO;
import com.pxmeta.user.entity.vo.UserVO;
import com.pxmeta.user.service.IPartyCategoryService;
import com.pxmeta.user.service.IUserBillService;
import com.pxmeta.user.service.IUserReportService;
import com.pxmeta.user.service.IUserService;
import io.swagger.annotations.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 语聊派对表 前端控制器
 * </p>
 *
 * @author wcl
 * @since 2022-06-25
 */
@RestController
@RequestMapping("/party/party")
@RequiredArgsConstructor
@Api(value = "语聊房",tags = "语聊房")

@Slf4j
public class PartyController {

    private final IPartyService partyService;
    private final AgoraClient agoraClient;
    private final IUserBillService userBillService;
    private final IUserReportService userReportService;
    private final IPartyUserCollectService partyUserCollectService;
    private final IUserService userService;

    private final RedisCache redisCache;

    private final IPartyUserService partyUserService;
    private final IAssociationService associationService;
    private final IPartyCategoryService partyCategoryService;
    private final IPartyDispatchService partyDispatchService;
    private final IPartyGiveGiftService partyGiveGiftService;

    /**
     * 分页获取语聊房列表
     * @return
     */
    @SaCheckLogin
    @ApiOperation(value = "分页获取语聊房列表")
    @ApiImplicitParams(
            value = {
                    @ApiImplicitParam(name = "page",value = "页码"),
                    @ApiImplicitParam(name = "size", value = "每页记录数"),
                    @ApiImplicitParam(name = "type", value = "类型：1推荐")
            }
    )
    @GetMapping("/findPage")
    public AjaxResult<List<Party>> findPage(@RequestParam Integer page,
                                            @RequestParam Integer size,
                                            @RequestParam(required = false) Integer type,
                                            @RequestParam(required = false) String keyword){
        Long userId = SecurityUtils.getUserId();
        User user = userService.getById(userId);
        //推荐
        LambdaQueryWrapper<Party> wrapper = Wrappers.lambdaQuery();
        //获取所有公会房间
        List<Association> associations = associationService.list();
        List<String> partyIds = Lists.newLinkedList();
        for (Association association : associations) {
            String partyId = association.getPartyIds();
            if (StringUtils.isNotBlank(partyId)){
                List<String> list = Arrays.asList(partyId.split(","));
                partyIds.addAll(list);
            }
        }

        ChannelResultVO channelResult = agoraClient.getChannelList(page, size).toJavaObject(ChannelResultVO.class);
        List<ChannelsVO> channels = channelResult.getChannels();
        List<String> channelIds = channels.stream().map(ChannelsVO::getChannelName).collect(Collectors.toList());
        channelIds.addAll(partyIds);

        if (CollectionUtil.isEmpty(channelIds)){
            return AjaxResult.success(Lists.newArrayList());
        }


        if (StringUtils.isNotBlank(keyword)){
            wrapper.and(w->w.like(Party::getTitle,keyword).or().like(Party::getNumber,keyword));
        }else {
            wrapper.eq(Party::getIsHidden, Boolean.FALSE);
        }

        //type如果是0，则是收藏
        if (type == null || type == -1){
            //根据热度降序

        }else if (type== 0){
            //获取收藏
            List<String> collectPartyIds = partyUserCollectService.findCollectPartyIds(userId);

            if (collectPartyIds.isEmpty()){
                return AjaxResult.success(Lists.newArrayList());
            }
            wrapper.clear();
            wrapper.in(Party::getId, collectPartyIds);
        }else if (type == 1){
            wrapper.eq(Party::getType, 3);
        }else if (type == -2) {
            //查询我的创建的厅。
            wrapper.clear();
            wrapper.eq(Party::getUserId, userId);
        }else if (type == -3) {
            Set<String> visitPartyIds = partyUserService.getVisitPartyIds(userId);
            wrapper.clear();
            channelIds.addAll(visitPartyIds);
        }else {
            wrapper.eq(Party::getType, type);
        }

        wrapper.in(Party::getId,channelIds);
        wrapper.orderByDesc(Party::getHot);

        List<Party> partyList = partyService.page(new Page<>(page, size),wrapper).getRecords();


        for (Party party : partyList) {
            Optional<ChannelsVO> first = channels.stream().filter(c -> c.getChannelName().equals(party.getId())).findFirst();
            if (first.isPresent()){
                ChannelsVO channelsVO = first.get();
                party.setOnlineCount(channelsVO.getUserCount());
            }else {
                party.setOnlineCount(0);
            }
            try{

                List<UserVO> users = Lists.newArrayList();
                ChannelUserVO userVO = redisCache.getCacheObject("party_userVo_" + party.getId());
                if (userVO == null){
                    userVO = agoraClient.getUsers(party.getId()).toJavaObject(ChannelUserVO.class);
                    redisCache.setCacheObject("party_userVo_"+party.getId(),userVO,30, TimeUnit.MINUTES);
                    List<Integer> usernames = userVO.getBroadcasters();
                    users = userService.getUserVOListByUsername(usernames);
                    redisCache.deleteObject("party_users_"+party.getId());
                    redisCache.setCacheList("party_users_"+party.getId(),users);
                }else {
                    users = redisCache.getCacheList("party_users_" + party.getId());
                }


                //List<UserVO> users = partyUserService.getPartyUsers(party.getId());
                Map<String, Object> map = agoraClient.getRtcToken(user.getUsername(), party.getId());
                party.setTokenMap(map);
                party.setUsers(users);
            }catch (Exception ignored){

            }


        }
        return AjaxResult.success(partyList);
    }


    @ApiOperation(value = "获取派单厅分类")
    @GetMapping("/getCategory")
    public AjaxResult<List<PartyCategory>> getCategoryList(){

        LambdaQueryWrapper<PartyCategory> wrapper = Wrappers.lambdaQuery();
        wrapper.orderByDesc(PartyCategory::getSort);
        List<PartyCategory> list = partyCategoryService.list(wrapper);

        return AjaxResult.success(list);
    }


    @GetMapping("/getPartyBox")
    @ApiOperation("获取房间弹框")
    public AjaxResult<AnchorVO> getPartyBox(){
        List<AnchorVO> anchorList = partyService.getAnchorList();
        if (anchorList.isEmpty()){
            return AjaxResult.success();
        }
        Collections.shuffle(anchorList);
        AnchorVO vo = anchorList.get(0);
        return AjaxResult.success(vo);
    }



    @ApiOperation(value = "随机获取可加入的派对id")
    @GetMapping("/getRandomPartyId")
    @SaCheckLogin
    public AjaxResult getRandomPartyId(@RequestParam(defaultValue = "6",required = false) Integer type){
        String partyId = partyService.getRandomPartyId(type);
        HashMap<String, String> map = Maps.newHashMap();
        map.put("partyId", partyId);
        return AjaxResult.success(map);
    }


    @GetMapping("/getPartyGiveGiftList")
    @SaCheckLogin
    @ApiOperation("获取房间幸福墙列表")
    public AjaxResult getPartyGiveGiftList(){
        List<GiftItemsVO> list = partyGiveGiftService.getPartyGiveGiftList();
        return AjaxResult.success(list);
    }

//    @ApiOperation(value = "获取要推送的陪陪用户列表")
//    @GetMapping("/getAccompanyUsers")
//    @SaCheckLogin
//    public AjaxResult getAccompanyUsers(@RequestParam String partyId,
//                                            @RequestParam Integer skillId,
//                                            @RequestParam Integer sex){
//        Long userId = SecurityUtils.getUserId();
//        List<User> list = userSkillService.sendAccompanyUsers(partyId, skillId, sex,null);
//        return AjaxResult.success(list);
//    }

    @SaCheckLogin
    @PostMapping("/reportParty")
    @ApiOperation("举报派对")
    public AjaxResult reportUser(@RequestBody ReportPartyDTO dto) {
        Long userId = SecurityUtils.getUserId();
        userReportService.report(dto,userId);
        return AjaxResult.success("举报成功！");
    }

    /**
     * @param partyId
     * @param type 0总榜 1周榜，2日榜
     * @return
     */
    @GetMapping("/getContributionList")
    @ApiOperation("获取贡献榜")
    @SaCheckLogin
    public AjaxResult<List<PartyUserBillVO>> getContributionList(@RequestParam Long partyId,
                                                                 @RequestParam(required = false) Integer type){
        List<PartyUserBillVO> list = userBillService.getContributionList(partyId,type);
        return AjaxResult.success(list);
    }

    @GetMapping("/getContributionTopThree")
    @ApiOperation("获取贡献榜前三")
    @SaCheckLogin
    public AjaxResult<List<PartyUserBillVO>> getContributionTopThree(@RequestParam Long partyId){
        List<PartyUserBillVO> list = userBillService.getContributionTopThree(partyId);
        return AjaxResult.success(list);
    }


    @GetMapping("/checkPartyIsLock")
    @ApiOperation("校验房间是否上锁")
    public AjaxResult checkPartyIsLock(@RequestParam String partyId){
        Party party = partyService.getById(partyId);
        String password = party.getPassword();
        boolean isLock = false;
        if (StringUtils.isNotBlank(password)){
            isLock = true;
        }
        HashMap<String, Object> map = Maps.newHashMap();
        map.put("isLock",isLock);
        return AjaxResult.success(map);
    }


    @PostMapping("/setPassword")
    @ApiOperation("设置房间密码")
    @SaCheckLogin
    public AjaxResult setPassword(@RequestBody SetPasswordDTO dto){
        partyService.setPassword(dto);
        return AjaxResult.success();
    }

    @GetMapping("/checkPassword")
    @ApiOperation("校验密码")
    @SaCheckLogin
    public AjaxResult checkPassword(
            @RequestParam String partyId,
            @RequestParam String password){
        Boolean success = partyService.checkPassword(partyId, password);
        Map<String, Object> map = Maps.newHashMap();
        map.put("isSuccess",success);
        return AjaxResult.success(map);
    }

    @DeleteMapping("/removePassword")
    @ApiOperation("取消房间密码")
    @SaCheckLogin
    public AjaxResult removePassword(@RequestParam String partyId){
        Party party = partyService.getById(partyId);
        party.setPassword("");
        partyService.updateById(party);
        return AjaxResult.success();
    }


    @GetMapping("/getCharmList")
    @ApiOperation("获取魅力榜")
    @SaCheckLogin
    public AjaxResult<List<PartyUserBillVO>> getCharmList(@RequestParam Long partyId,
                                                          @RequestParam(required = false) Integer type){
        List<PartyUserBillVO> list = userBillService.getCharmList(partyId, type);
        return AjaxResult.success(list);
    }


    @PutMapping("/setGiftEffects")
    @ApiOperation("设置礼物开关")
    public AjaxResult setGiftEffects(@RequestParam String partyId,
                                     @RequestParam Boolean isOpen){
        String username = SecurityUtils.getUsername();
        PartyUser partyUser = partyUserService.getPartyUser(partyId, username);
        partyUser.setIsOpenGiftEffects(isOpen);
        partyUserService.updateById(partyUser);
        return AjaxResult.success();
    }


    @GetMapping("/checkIsOpenGiftEffects")
    @ApiOperation("判断是否开启礼物特效")
    public AjaxResult checkIsOpenGiftEffects(@RequestParam String partyId){
        String username = SecurityUtils.getUsername();
        PartyUser partyUser = partyUserService.getPartyUser(partyId, username);
        HashMap<String, Object> map = Maps.newHashMap();
        map.put("isOpen", partyUser.getIsOpenGiftEffects());
        return AjaxResult.success(map);
    }


//    @GetMapping("/getCharmItemList")
//    @ApiOperation("获取魅力值明细")
//    @SaCheckLogin
//    public AjaxResult getCharmItemList(@RequestParam){
//
//        return AjaxResult.success();
//    }


    @PostMapping("/createParty")
    @ApiOperation(value = "创建语聊房派对")
    @SaCheckLogin
    public AjaxResult<Party> createParty(@RequestBody CreatePartyDTO dto){
        Long userId = SecurityUtils.getUserId();
        String username = SecurityUtils.getUsername();
        Party party = partyService.createParty(dto, userId);
        try{
            log.info("创建房间: username:{}, partyId:{}", username, party.getId());
            Map<String, Object> map = agoraClient.getRtcToken(username, party.getId());
            party.setTokenMap(map);
        }catch (Exception e){
        }
        return AjaxResult.success(party);
    }


    @DeleteMapping("/dissolutionParty")
    @ApiOperation(value = "解散派对")
    @SaCheckLogin
    public AjaxResult dissolutionParty(@RequestParam Long partyId){
        Long userId = SecurityUtils.getUserId();
        partyService.dissolution(userId, partyId);
        return AjaxResult.success();
    }

    @DeleteMapping("/singOutParty")
    @ApiOperation(value = "退出派对")
    @SaCheckLogin
    public AjaxResult signOutParty(@RequestParam Long partyId){
        Long userId = SecurityUtils.getUserId();
        partyService.signOut(userId, partyId);
        return AjaxResult.success();
    }


    @PostMapping("/joinParty")
    @ApiOperation(value = "加入派对")
    @SaCheckLogin
    public AjaxResult joinParty(@RequestBody JoinPartyDTO dto){
        String partyId = dto.getPartyId();
        Long userId = SecurityUtils.getUserId();
        partyService.joinParty(partyId, userId, PartyUserRoleEnum.NORMAL.getRole());
        return AjaxResult.success();
    }


    @GetMapping("/getPartyDetail")
    @ApiOperation(value = "获取派对详情")
    @SaCheckLogin
    public AjaxResult getPartyDetail(@RequestParam Long partyId){
        Party party = partyService.getById(partyId);
        if (null == party){
            return AjaxResult.error("房间已被关闭！");
        }
        String username = SecurityUtils.getUsername();
        Map<String, Object> map = agoraClient.getRtcToken(username, party.getId());
        party.setTokenMap(map);
        User creator = userService.getById(party.getUserId());
        party.setCreatorUsername(creator.getUsername());
        return AjaxResult.success(party);
    }


    @PutMapping("/editParty")
    @ApiOperation("编辑派对")
    @SaCheckLogin
    public AjaxResult editParty(@RequestBody EditPartyDTO dto){

        String notice = dto.getNotice();
        String title = dto.getTitle();
        Long partyId = dto.getPartyId();
        Party party = partyService.getById(partyId);
        if (StringUtils.isNotBlank(notice)){
            party.setNotice(notice);
        }
        if (StringUtils.isNotBlank(title)){
            party.setTitle(title);
        }
        if (StringUtils.isNotBlank(dto.getImgUrl())){
            party.setImgUrl(dto.getImgUrl());
        }
        if (StringUtils.isNotBlank(dto.getBgUrl())){
            party.setBgUrl(dto.getBgUrl());
        }
        partyService.updateById(party);

        return AjaxResult.success();
    }


    @PostMapping("/dispatch")
    @ApiOperation("发起派单")
    @SaCheckLogin
    public AjaxResult dispatch(@RequestBody DispatchDTO dto){
        partyDispatchService.dispatch(dto);
        return AjaxResult.success();
    }


    @PostMapping("/batchDispatchByIds")
    @ApiOperation("批量获取派单信息")
    @SaCheckLogin
    public AjaxResult<List<PartyDispatch>> batchDispatchStatus(@RequestBody BatchDispatchListDTO dto){
        List<Long> ids = dto.getDispatchIds();
        if (ids.isEmpty()){
            return AjaxResult.success(Lists.newArrayList());
        }
        List<PartyDispatch> list = partyDispatchService.listByIds(ids);
        return AjaxResult.success(list);
    }


    @GetMapping("/getDispatchDetail")
    @ApiOperation("获取派单信息")
    @SaCheckLogin
    public AjaxResult<PartyDispatch> getDispatchDetail(@RequestParam String partyId){
        PartyDispatch detail = partyDispatchService.getDispatchDetail(partyId);
        return AjaxResult.success(detail);
    }


    @PostMapping("/cancelDispatch")
    @ApiOperation("取消派单")
    @SaCheckLogin
    public AjaxResult cancelDispatch(@RequestBody OperateDispatchDTO dto){
        partyDispatchService.cancelDispatch(dto);
        return AjaxResult.success();
    }

    @PostMapping("/completeDispatch")
    @ApiOperation("完成派单")
    @SaCheckLogin
    public AjaxResult completeDispatch(@RequestBody OperateDispatchDTO dto){
        partyDispatchService.completeDispatch(dto);
        return AjaxResult.success();
    }

    @GetMapping("/getAnchorList")
    @ApiOperation("获取推荐主播列表")
    public AjaxResult getAnchorList(){
        List<AnchorVO> list = partyService.getAnchorList();
        return AjaxResult.success(list);
    }


    @PostMapping("/addAdmin")
    @ApiOperation("添加管理员")
    public AjaxResult addAdmin(@RequestBody OperateAdminDTO dto){
        String adminUsername = dto.getAdminUsername();
        String partyId = dto.getPartyId();
        partyService.addAdmin(partyId,adminUsername,dto.getType());
        return AjaxResult.success();
    }

    @GetMapping("/getAdminList")
    @ApiOperation("获取管理员列表")
    public AjaxResult<List<User>> getAdminList(@RequestParam String partyId){
        List<User> users = partyService.getAdminList(partyId);
        return AjaxResult.success(users);
    }

    @GetMapping("/getSuperAdminList")
    @ApiOperation("获取超级管理员列表")
    public AjaxResult<List<User>> getSuperAdminList(@RequestParam String partyId){
        List<User> users = partyService.getSuperAdminList(partyId);
        return AjaxResult.success(users);
    }

    @GetMapping("/getAssociationRole")
    @ApiOperation("获取公会角色")
    public AjaxResult getAssociationRole(){
        Long userId = SecurityUtils.getUserId();
        Integer role = partyService.getAssociationRole(userId);
        PartyRoleVO vo = new PartyRoleVO();
        vo.setRole(role);
        return AjaxResult.success(vo);
    }

    @PostMapping("/collectParty")
    @ApiOperation("收藏房间")
    @SaCheckLogin
    public AjaxResult collectParty(@RequestBody CollectPartyDTO dto){
        Long userId = SecurityUtils.getUserId();
        partyUserCollectService.collect(userId, dto.getPartyId());
        return AjaxResult.success();
    }


    @GetMapping("/findIsCollect")
    @ApiOperation("查询是否收藏")
    @SaCheckLogin
    public AjaxResult findIsCollect(@RequestParam String partyId){
        Long userId = SecurityUtils.getUserId();
        boolean isCollect = partyUserCollectService.findIsCollect(userId, partyId);
        Map<String, Object> map = Maps.newHashMap();
        map.put("isCollect", isCollect);
        return AjaxResult.success(map);
    }

    @DeleteMapping("/removeAdmin")
    @ApiOperation("移出管理员")
    public AjaxResult removeAdmin(@RequestBody OperateAdminDTO dto){
        String adminUsername = dto.getAdminUsername();
        String partyId = dto.getPartyId();
        partyService.removeAdmin(partyId, adminUsername);
        return AjaxResult.success();
    }


}
